/*
 * Copyright © 2019-2020  Whale Cloud, Inc. All Rights Reserved.
 *
 * Notice: Whale Cloud Inc copyrights this specification.
 * No part of this specification may be reproduced in any form or means,
 * without the prior written consent of Whale Cloud Inc.
 *
 */
package com.wteam.modules.system.service.impl;

import com.wteam.modules.system.domain.DevelopPlanCreditTypeMap;
import com.wteam.modules.system.domain.dto.CusPage;
import com.wteam.modules.system.domain.dto.DeptDTO;
import com.wteam.modules.system.domain.dto.DevelopPlanCreditTypeMapDTO;
import com.wteam.modules.system.domain.mapper.DeptMapper;
import com.wteam.modules.system.domain.mapper.DevelopPlanCreditTypeMapMapper;
import com.wteam.modules.system.repository.DeptRepository;
import com.wteam.modules.system.repository.DevelopPlanCreditTypeMapRepository;
import com.wteam.modules.system.service.DevelopPlanService;
import com.wteam.modules.system.domain.DevelopPlan;
import com.wteam.modules.system.domain.dto.DevelopPlanDTO;
import com.wteam.modules.system.domain.criteria.DevelopPlanQueryCriteria;
import com.wteam.modules.system.domain.mapper.DevelopPlanMapper;
import com.wteam.modules.system.repository.DevelopPlanRepository;
import com.wteam.exception.BadRequestException;
import com.wteam.utils.*;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cache.annotation.*;
import lombok.RequiredArgsConstructor;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 专业培养方案 业务实现层.
 *
 * @author herry_wong
 * @since 2020-12-29
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "developPlan")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class DevelopPlanServiceImpl implements DevelopPlanService {

    private final DevelopPlanRepository developPlanRepository;

    private final DevelopPlanMapper developPlanMapper;

    private final RedisUtils redisUtils;

    private final DeptRepository deptRepository;
    private final DeptMapper deptMapper;

    private final DevelopPlanCreditTypeMapRepository developPlanCreditTypeMapRepository;
    private final DevelopPlanCreditTypeMapMapper developPlanCreditTypeMapMapper;

    @Override
    public Map<String,Object> queryAll(DevelopPlanQueryCriteria criteria, Pageable pageable){
        Page<DevelopPlan> page = developPlanRepository.findAll((root, criteriaQuery, criteriaBuilder) ->  QueryHelper.andPredicate(root, criteria, criteriaBuilder), pageable);
        Page<DevelopPlanDTO> developPlanDTOPage = page.map(developPlanMapper::toDto);
        Page<DevelopPlanDTO> cusPage = new CusPage<>(developPlanDTOPage);
        for (DevelopPlanDTO developPlanDTO: cusPage){
            Collections.replaceAll(cusPage.getContent(),
                    developPlanDTO,
                    findDTOById(developPlanDTO.getId()));

        }
        return PageUtil.toPage(cusPage);
    }

    @Override
    public List<DevelopPlanDTO> queryAll(DevelopPlanQueryCriteria criteria){
        return developPlanMapper.toDto(developPlanRepository.findAll((root, criteriaQuery, criteriaBuilder) ->  QueryHelper.andPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
//    @Cacheable(key = "'id:' + #p0")
    public DevelopPlanDTO findDTOById(Long id) {
        DevelopPlan developPlan = developPlanRepository.findById(id).orElse(null);
        ValidUtil.notNull(developPlan, DevelopPlan.ENTITY_NAME, "id", id);

        DevelopPlanDTO developPlanDTO = developPlanMapper.toDto(developPlan);

        developPlanDTO.setSubject(deptMapper.toDto(deptRepository.findByIdNoLogic(developPlanDTO.getSubjectId())));
        DevelopPlanCreditTypeMap exampleMap = new DevelopPlanCreditTypeMap();
        exampleMap.setPlanId(id);
        List<DevelopPlanCreditTypeMap> developPlanCreditTypeMaps = developPlanCreditTypeMapRepository.findAll(Example.of(exampleMap));
        developPlanDTO.setDevelopPlanCreditTypeMapDTOS(new HashSet<>(developPlanCreditTypeMapMapper.toDto(
                developPlanCreditTypeMaps
        )));
        return developPlanDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DevelopPlanDTO create(DevelopPlan resources) {
        DevelopPlan developPlan = developPlanRepository.save(resources);
        DevelopPlanDTO developPlanDTO = developPlanMapper.toDto(developPlan);
        if (resources.getDevelopPlanCreditTypeMaps() != null && resources.getDevelopPlanCreditTypeMaps().size() != 0){
            Set<DevelopPlanCreditTypeMapDTO> developPlanCreditTypeMapDTOS = new HashSet<>();
            for (DevelopPlanCreditTypeMap developPlanCreditTypeMap : resources.getDevelopPlanCreditTypeMaps()){
                developPlanCreditTypeMap.setPlanId(developPlan.getId());
                developPlanCreditTypeMapDTOS.add(developPlanCreditTypeMapMapper.toDto(
                        developPlanCreditTypeMapRepository.save(developPlanCreditTypeMap)
                ));
            }
            developPlanDTO.setDevelopPlanCreditTypeMapDTOS(developPlanCreditTypeMapDTOS);
        }
        return developPlanMapper.toDto(developPlanRepository.save(resources));
    }

    @Override
    @CacheEvict(key = "'id:' + #p0.id")
    @Transactional(rollbackFor = Exception.class)
    public void update(DevelopPlan resources) {
        DevelopPlan developPlan = developPlanRepository.findById(resources.getId()).orElse(null);
        ValidUtil.notNull(developPlan, DevelopPlan.ENTITY_NAME, "id",resources.getId());
        if (resources.getDevelopPlanCreditTypeMaps() != null){
            DevelopPlanCreditTypeMap exampleMap = new DevelopPlanCreditTypeMap();
            exampleMap.setPlanId(resources.getId());
            List<DevelopPlanCreditTypeMap> developPlanCreditTypeMaps = developPlanCreditTypeMapRepository.findAll(Example.of(exampleMap));
            developPlanCreditTypeMapRepository.logicDeleteInBatch(developPlanCreditTypeMaps);

            Set<DevelopPlanCreditTypeMapDTO> developPlanCreditTypeMapDTOS = new HashSet<>();
            for (DevelopPlanCreditTypeMap developPlanCreditTypeMap : resources.getDevelopPlanCreditTypeMaps()){
                developPlanCreditTypeMap.setPlanId(developPlan.getId());
                developPlanCreditTypeMapDTOS.add(developPlanCreditTypeMapMapper.toDto(
                        developPlanCreditTypeMapRepository.save(developPlanCreditTypeMap)
                ));
            }
        }

        developPlan.copy(resources);
        developPlanRepository.save(developPlan);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Set<Long> ids) {

        for (Long id : ids){
            DevelopPlanCreditTypeMap exampleMap = new DevelopPlanCreditTypeMap();
            exampleMap.setPlanId(id);
            List<DevelopPlanCreditTypeMap> developPlanCreditTypeMaps = developPlanCreditTypeMapRepository.findAll(Example.of(exampleMap));
            developPlanCreditTypeMapRepository.logicDeleteInBatch(developPlanCreditTypeMaps);
        }
        redisUtils.delByKeys("developPlan::id:", ids);
        developPlanRepository.logicDeleteInBatchById(ids);
    }

    @Override
    public void download(List<DevelopPlanDTO> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (DevelopPlanDTO developPlan : queryAll) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("专业id", developPlan.getSubjectId());
            map.put("创建时间", developPlan.getCreatedAt());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}